home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / TELNET.C < prev    next >
C/C++ Source or Header  |  1989-08-30  |  8KB  |  374 lines

  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "socket.h"
  5. #include "telnet.h"
  6. #include "session.h"
  7. #include "proc.h"
  8. #include "tty.h"
  9. #include "commands.h"
  10. #include "netuser.h"
  11.  
  12. #define    CTLZ    26
  13.  
  14. extern char Nospace[];
  15. extern char Badhost[];
  16.  
  17. static void doopt __ARGS((struct telnet *tn,char opt));
  18. static void dontopt __ARGS((struct telnet *tn,char opt));
  19. static void willopt __ARGS((struct telnet *tn,char opt));
  20. static void wontopt __ARGS((struct telnet *tn,char opt));
  21. static void answer __ARGS((struct telnet *tn,int r1,int r2));
  22.  
  23. int Refuse_echo = 0;
  24. int Unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  25.  
  26. #ifdef    DEBUG
  27. char *T_options[] = {
  28.     "Transmit Binary",
  29.     "Echo",
  30.     "",
  31.     "Suppress Go Ahead",
  32.     "",
  33.     "Status",
  34.     "Timing Mark"
  35. };
  36. #endif
  37.  
  38. /* Execute user telnet command */
  39. int
  40. dotelnet(argc,argv,p)
  41. int argc;
  42. char *argv[];
  43. void *p;
  44. {
  45.     struct session *sp;
  46.     struct telnet tn;
  47.     struct sockaddr_in fsocket;
  48.     struct mbuf *bp;
  49.     char *cp;
  50.  
  51.     /* Allocate a session descriptor */
  52.     if((sp = newsession(argv[1],TELNET)) == NULLSESSION){
  53.         printf("Too many sessions\n");
  54.         freeargs(argc,argv);
  55.         return 1;
  56.     }
  57.     /* Initialize Telnet protocol descriptor */
  58.     memset((char *)&tn,0,sizeof(tn));
  59.     tn.output = Curproc;
  60.     tn.session = sp;    /* Upward pointer */
  61.     sp->cb.telnet = &tn;    /* Downward pointer */
  62.  
  63.     fsocket.sin_family = AF_INET;
  64.     if(argc < 3)
  65.         fsocket.sin_port = IPPORT_TELNET;
  66.     else
  67.         fsocket.sin_port = atoi(argv[2]);
  68.  
  69.     freeargs(argc,argv);
  70.     Current = sp;
  71.     Mode = CONV_MODE;
  72.     if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  73.         printf(Badhost,sp->name);
  74.         freesession(sp);
  75.         return 1;
  76.     }
  77.     if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  78.         printf("Can't create socket\n");
  79.         freesession(sp);
  80.         return 1;
  81.     }
  82.     printf("Trying %s...\n",psocket((struct sockaddr *)&fsocket));
  83.     if(connect(sp->s,(char *)&fsocket,SOCKSIZE) == -1){
  84.         cp = sockerr(sp->s);
  85.         printf("Telnet session %u connect failed: %s\n",
  86.          (unsigned)(sp-Sessions),cp != NULLCHAR ? cp : "");
  87.         freesession(sp);
  88.         return 1;
  89.     }
  90.     printf("Telnet session %u connected to %s\n",
  91.         (unsigned)(sp-Sessions),sp->name);
  92.     /* Fork off the receiver process */
  93.     tn.input = newproc("tel_in",512,tel_input,0,&tn,NULL);
  94.  
  95.     /* Now send whatever's typed on the terminal */
  96.     for(;;){
  97.         while(sp->input == NULLBUF)
  98.             if(pwait(&sp->input) == -1)
  99.                 goto quit;
  100.  
  101.         bp = dequeue(&sp->input);
  102.  
  103.         /* If we're doing our own echoing and recording is enabled,
  104.          * record it
  105.          */
  106.         if(!tn.remote[TN_ECHO] && sp->record != NULLFILE)
  107.             write_p(sp->record,bp);
  108.         if(send_mbuf(sp->s,bp,0,NULLCHAR,0) == -1)
  109.             break;
  110.     }
  111. quit:    close_s(sp->s);
  112.     killproc(tn.input);
  113.     freesession(sp);
  114.     return 0;
  115. }
  116.  
  117. /* User telnet receive task, started by user telnet command */
  118. void
  119. tel_input(unused,tn1,p)
  120. int unused;
  121. void *tn1;
  122. void *p;
  123. {
  124.     int c;
  125.     FILE *record;
  126.     struct session *sp;
  127.     char *cp;
  128.     struct mbuf *bp = NULLBUF;
  129.     struct telnet *tn;
  130.  
  131.     tn = (struct telnet *)tn1;
  132.     sp = tn->session;
  133.  
  134.     while((c = recvchar(sp->s,&bp)) != -1){
  135.  
  136.         /* Suspend output if we're not current */
  137.         while(Current != sp || Mode != CONV_MODE)
  138.             if(pwait(sp) == -1)
  139.                 goto quit;
  140.  
  141.         if(uchar(c) == IAC){
  142.             /* IAC received, get command sequence */
  143.             c = recvchar(sp->s,&bp);
  144.             switch(uchar(c)){
  145.             case WILL:
  146.                 willopt(tn,recvchar(sp->s,&bp));
  147.                 break;
  148.             case WONT:
  149.                 wontopt(tn,recvchar(sp->s,&bp));
  150.                 break;
  151.             case DO:
  152.                 doopt(tn,recvchar(sp->s,&bp));
  153.                 break;
  154.             case DONT:
  155.                 dontopt(tn,recvchar(sp->s,&bp));
  156.                 break;
  157.             case IAC:    /* Escaped IAC */
  158.                 putchar(IAC);
  159.                 if((record = sp->record) != NULLFILE)
  160.                     putc(IAC,record);
  161.                 break;
  162.             }
  163.         } else {
  164.             /* Ordinary character */
  165.             if(!tn->remote[TN_TRANSMIT_BINARY])
  166.                 c &= 0x7f;
  167.  
  168.             putchar(c);
  169.             if((record = sp->record) != NULLFILE)
  170.                 putc(c,record);
  171.         }
  172.     }
  173. quit:    /* Close seen from remote host */
  174.     free_p(bp);
  175.     cp = sockerr(sp->s);
  176.     printf("Telnet session %u closed: %s\n", (unsigned)(sp - Sessions),
  177.      cp != NULLCHAR ? cp : "EOF");
  178.     close_s(sp->s);
  179.     killproc(tn->output);
  180.     freesession(sp);
  181. }
  182.  
  183. /* File uploading task */
  184. void
  185. tel_upload(unused,sp1,p)
  186. int unused;
  187. void *sp1;
  188. void *p;
  189. {
  190.     struct telnet *tn;
  191.     struct session *sp;
  192.     struct mbuf *bp;
  193.     int c;
  194.     char *cp;
  195.  
  196.     sp = (struct session *)sp1;
  197.     tn = sp->cb.telnet;
  198.  
  199.     /* Initialize current output buffer */
  200.     bp = alloc_mbuf(BUFSIZ);
  201.     cp = bp->data;
  202.  
  203.     while((c = getc(sp->upload)) != EOF){
  204.         if(bp->cnt >= BUFSIZ-2){
  205.             /* If buffer can't take two more characters, flush
  206.              * it and get a new one. This allows for a cr/lf
  207.              * at the end of the buffer.
  208.              */
  209.             send_mbuf(sp->s,bp,0,NULLCHAR,0);
  210.             bp = alloc_mbuf(BUFSIZ);
  211.             cp = bp->data;
  212.         }                
  213.         /* Copy to output, translating newlines to CR/LF */
  214.         if(c == '\n'){
  215.             *cp++ = '\r';
  216.             bp->cnt++;
  217.         }
  218.         *cp++ = c;
  219.         bp->cnt++;
  220.     }
  221.     /* Send last buffer, if not empty */
  222.     if(bp->cnt != 0)
  223.         send_mbuf(sp->s,bp,0,NULLCHAR,0);
  224.     else
  225.         free_p(bp);
  226.  
  227.     fclose(sp->upload);
  228.     sp->upload = NULLFILE;
  229.     free(sp->ufile);
  230.     sp->ufile = NULLCHAR;
  231.     tn->upload = NULLPROC;
  232. }
  233. /* The guts of the actual Telnet protocol: negotiating options */
  234. static
  235. void
  236. willopt(tn,opt)
  237. struct telnet *tn;
  238. char opt;
  239. {
  240.     int ack;
  241.  
  242. #ifdef    DEBUG
  243.     printf("recv: will ");
  244.     if(uchar(opt) <= NOPTIONS)
  245.         printf("%s\n",T_options[opt]);
  246.     else
  247.         printf("%u\n",opt);
  248. #endif
  249.     
  250.     switch(uchar(opt)){
  251.     case TN_TRANSMIT_BINARY:
  252.     case TN_ECHO:
  253.     case TN_SUPPRESS_GA:
  254.         if(tn->remote[uchar(opt)] == 1)
  255.             return;        /* Already set, ignore to prevent loop */
  256.         if(uchar(opt) == TN_ECHO){
  257.             if(Refuse_echo){
  258.                 /* User doesn't want to accept */
  259.                 ack = DONT;
  260.                 break;
  261.             } else
  262.                 ttysetmode(0);        /* Put tty into raw mode */
  263.         }
  264.         tn->remote[uchar(opt)] = 1;
  265.         ack = DO;            
  266.         break;
  267.     default:
  268.         ack = DONT;    /* We don't know what he's offering; refuse */
  269.     }
  270.     answer(tn,ack,opt);
  271. }
  272. static void
  273. wontopt(tn,opt)
  274. struct telnet *tn;
  275. char opt;
  276. {
  277. #ifdef    DEBUG
  278.     printf("recv: wont ");
  279.     if(uchar(opt) <= NOPTIONS)
  280.         printf("%s\n",T_options[uchar(opt)]);
  281.     else
  282.         printf("%u\n",uchar(opt));
  283. #endif
  284.     if(uchar(opt) <= NOPTIONS){
  285.         if(tn->remote[uchar(opt)] == 0)
  286.             return;        /* Already clear, ignore to prevent loop */
  287.         tn->remote[uchar(opt)] = 0;
  288.         if(uchar(opt) == TN_ECHO)
  289.             ttysetmode(TTY_ECHO|TTY_EDIT);    /* Put tty into cooked mode */
  290.     }
  291.     answer(tn,DONT,opt);    /* Must always accept */
  292. }
  293. static void
  294. doopt(tn,opt)
  295. struct telnet *tn;
  296. char opt;
  297. {
  298.     int ack;
  299.  
  300. #ifdef    DEBUG
  301.     printf("recv: do ");
  302.     if(uchar(opt) <= NOPTIONS)
  303.         printf("%s\n",T_options[uchar(opt)]);
  304.     else
  305.         printf("%u\n",uchar(opt));
  306. #endif
  307.     switch(uchar(opt)){
  308. #ifdef    FUTURE    /* Use when local options are implemented */
  309.         if(tn->local[uchar(opt)] == 1)
  310.             return;        /* Already set, ignore to prevent loop */
  311.         tn->local[uchar(opt)] = 1;
  312.         ack = WILL;
  313.         break;
  314. #endif
  315.     default:
  316.         ack = WONT;    /* Don't know what it is */
  317.     }
  318.     answer(tn,ack,opt);
  319. }
  320. static void
  321. dontopt(tn,opt)
  322. struct telnet *tn;
  323. char opt;
  324. {
  325. #ifdef    DEBUG
  326.     printf("recv: dont ");
  327.     if(uchar(opt) <= NOPTIONS)
  328.         printf("%s\n",T_options[uchar(opt)]);
  329.     else
  330.         printf("%u\n",uchar(opt));
  331. #endif
  332.     if(uchar(opt) <= NOPTIONS){
  333.         if(tn->local[uchar(opt)] == 0){
  334.             /* Already clear, ignore to prevent loop */
  335.             return;
  336.         }
  337.         tn->local[uchar(opt)] = 0;
  338.     }
  339.     answer(tn,WONT,opt);
  340. }
  341. static void
  342. answer(tn,r1,r2)
  343. struct telnet *tn;
  344. int r1,r2;
  345. {
  346.     char s[3];
  347.  
  348. #ifdef    DEBUG
  349.     switch(r1){
  350.     case WILL:
  351.         printf("sent: will ");
  352.         break;
  353.     case WONT:
  354.         printf("sent: wont ");
  355.         break;
  356.     case DO:
  357.         printf("sent: do ");
  358.         break;
  359.     case DONT:
  360.         printf("sent: dont ");
  361.         break;
  362.     }
  363.     if(r2 <= 6)
  364.         printf("%s\n",T_options[r2]);
  365.     else
  366.         printf("%u\n",r2);
  367. #endif
  368.  
  369.     s[0] = IAC;
  370.     s[1] = r1;
  371.     s[2] = r2;
  372.     send(tn->session->s,s,3,0);
  373. }
  374.